home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / TELNET.C < prev    next >
Text File  |  1993-08-09  |  10KB  |  458 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <time.h>
  4. #ifdef    __TURBOC__
  5. #include <io.h>
  6. #endif
  7. #include "global.h"
  8. #include "config.h"
  9. #include "mbuf.h"
  10. #include "socket.h"
  11. #include "telnet.h"
  12. #include "session.h"
  13. #include "proc.h"
  14. #include "tty.h"
  15. #include "commands.h"
  16. #include "netuser.h"
  17. #include "clients.h"
  18.  
  19. static int near gen_telnet __ARGS((char *name,int ipport,int bbs));
  20.  
  21. static int Refuse_echo = 0;
  22. static int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  23.  
  24. #ifdef DEBUG
  25. char *T_options[] = {
  26.     "Transmit Binary",
  27.     "Echo",
  28.     "",
  29.     "Suppress Go Ahead",
  30.     "",
  31.     "Status",
  32.     "Timing Mark"
  33. };
  34. #endif
  35.  
  36. #ifdef MAILBOX
  37. /* Execute user BBS command */
  38. int
  39. dobbs(int argc,char **argv,void *p)
  40. {
  41.     if(Ip_addr == 0) {
  42.         tputs(Noipaddr);
  43.         return -1;
  44.     }
  45.     return gen_telnet("LocBBS",IPPORT_TELNET,TRUE);
  46. }
  47. #endif
  48.  
  49. /* Execute user chat command */
  50. int
  51. dochat(int argc,char **argv,void *p)
  52. {
  53.     return gen_telnet(argv[1],IPPORT_TTYLINK,FALSE);
  54. }
  55.  
  56. /* Execute user telnet command */
  57. int
  58. dotelnet(int argc,char **argv,void *p)
  59. {
  60.     int arg = (argc < 3) ? IPPORT_TELNET : atoi(argv[2]);
  61.  
  62.     return gen_telnet(argv[1],arg,FALSE);
  63. }
  64.  
  65. static int near
  66. gen_telnet(char *name,int ipport,int bbs)
  67. {
  68.     int split = 0;
  69.     struct session *sp;
  70.     struct sockaddr_in fsocket;
  71.  
  72.     switch(ipport) {
  73.     case IPPORT_TELNET:
  74.     case IPPORT_TTYLINK:
  75.     case IPPORT_CONVERS:
  76.         split = 1;
  77.         break;
  78.     }
  79.     /* Allocate a session descriptor */
  80.     if((sp = newsession(name,TELNET,split | SWAP)) == NULLSESSION) {
  81.         tputs(Nosess);
  82.         return 1;
  83.     }
  84.     fsocket.sin_family = AF_INET;
  85.     fsocket.sin_port = ipport;
  86.  
  87.     if(bbs == TRUE) {
  88.         fsocket.sin_addr.s_addr = Ip_addr;
  89.     } else {
  90.         strlwr(sp->name);
  91.         tprintf("Resolving %s... ",sp->name);
  92.  
  93.         if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  94.             tprintf(Badhost,sp->name);
  95.             goto quit;
  96.         }
  97.     }
  98.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  99.         tputs(Nosocket);
  100.         goto quit;
  101.     }
  102.     if(!(tel_connect(sp,(char *)&fsocket,SOCKSIZE)))
  103.         return 0;
  104. quit:
  105.     keywait(NULLCHAR,1);
  106.     freesession(sp);
  107.     return 1;
  108. }
  109.  
  110. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  111. int
  112. tel_connect(struct session *sp,char *fsocket,int len)
  113. {
  114.     struct telnet tn;
  115.  
  116. /*    struct sockaddr_in *lsocket = (struct sockaddr_in *)fsocket;    */
  117.  
  118.     memset(&tn,0,sizeof(struct telnet));
  119.  
  120.     tn.eolmode = Tn_cr_mode;
  121.     tn.session = sp;                /* Upward pointer */
  122.     sp->cb.telnet = &tn;            /* Downward pointer */
  123.     sockmode(sp->s,SOCK_ASCII);        /* Default to ascii mode */
  124.  
  125.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  126.     if(connect(sp->s,fsocket,len) == -1) {
  127.         tprintf("%s session failed: %s errno %d\n",
  128.             Sestypes[sp->type], sockerr(sp->s),errno);
  129.         return 1;
  130.     }
  131.     tprintf("%s session connected to %s\n",Sestypes[sp->type],sp->name);
  132.  
  133.     log(sp->s,9983,"%4.4s connect",Sestypes[sp->type]);
  134.  
  135. /*    cli_login(lsocket->sin_port,(void *)&tn);                        */
  136.  
  137.     tnrecv(&tn);
  138.     return 0;
  139. }
  140.  
  141. /* Telnet input routine, common to both telnet and ttylink */
  142. void
  143. tnrecv(struct telnet *tn)
  144. {
  145.     char *cp = NULLCHAR;
  146.     struct session *sp = tn->session;
  147.     int c, s = sp->s;
  148.  
  149.     /* Fork off the transmit process */
  150.     sp->proc1 = newproc("tnrecv",768,tel_output,0,tn,NULL,0);
  151.  
  152.     /* Process input on the connection */
  153.     while((c = recvchar(s)) != -1){
  154.         if(c != IAC){
  155.             /* Ordinary character */
  156.             usputc(Curproc->output,c);
  157.             continue;
  158.         }
  159.         /* IAC received, get command sequence */
  160.         c = recvchar(s);
  161.         switch(c){
  162.         case WILL:
  163.             c = recvchar(s);
  164.             willopt(tn,c);
  165.             break;
  166.         case WONT:
  167.             c = recvchar(s);
  168.             wontopt(tn,c);
  169.             break;
  170.         case DO:
  171.             c = recvchar(s);
  172.             doopt(tn,c);
  173.             break;
  174.         case DONT:
  175.             c = recvchar(s);
  176.             dontopt(tn,c);
  177.             break;
  178.         case IAC:    /* Escaped IAC */
  179.             usputc(Curproc->output,IAC);
  180.             break;
  181.         }
  182.     }
  183.     /* A close was received from the remote host.
  184.      * Notify the user, kill the output task and wait for a response
  185.      * from the user before freeing the session.
  186.      */
  187.     sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
  188.  
  189.     if((cp = sockerr(s)) == NULLCHAR) {
  190.         cp = "EOF";
  191.     }
  192.     tprintf("%s session closed: %s at %s",
  193.         Sestypes[sp->type],cp,ctime(&currtime));
  194.  
  195.     log(sp->s,9983,"%4.4s closed %s",Sestypes[sp->type],cp);
  196.  
  197.     killproc(sp->proc1);
  198.     sp->proc1 = NULLPROC;
  199.     keywait(NULLCHAR,1);
  200.     freesession(sp);
  201. }
  202.  
  203. /* User telnet output task, started by user telnet command */
  204. static void
  205. tel_output(int unused,void *tn1,void *p)
  206. {
  207.     int c;
  208.     struct telnet *tn = (struct telnet *)tn1;
  209.     struct session *sp = tn->session;
  210.  
  211.     /* Send whatever's typed on the terminal */
  212.     while((c = recvchar(sp->input)) != -1) {
  213.         usputc(sp->s,c);
  214.  
  215.         if(!tn->remote[TN_ECHO] && sp->record != NULLFILE) {
  216.             fputc(c,sp->record);
  217.         }
  218.         /* By default, output is transparent in remote echo mode.
  219.          * If eolmode is set, turn a cr into cr-null.
  220.          * This can only happen when in remote echo (raw) mode, since
  221.          * the tty driver normally maps \r to \n in cooked mode.
  222.          */
  223.         if(c == '\r' && tn->eolmode) {
  224.             usputs(sp->s,"\0");
  225.         }
  226.         if(tn->remote[TN_ECHO]) {
  227.             usflush(sp->s);
  228.         }
  229.     }
  230.     /* Make sure our parent doesn't try to kill us after we exit */
  231.     sp->proc1 = NULLPROC;
  232. }
  233.  
  234. int
  235. doecho(int argc,char **argv,void *p)
  236. {
  237.     if(argc < 2) {
  238.         tprintf("Echo %s\n",Refuse_echo ? "refuse" : "accept");
  239.     } else {
  240.         switch(*argv[1]) {
  241.             case 'r':
  242.                 Refuse_echo = 1;
  243.                 break;
  244.             case 'a':
  245.                 Refuse_echo = 0;
  246.                 break;
  247.             default:
  248.                 tputs("Usage: echo <refuse|accept>\n");
  249.                 return -1;
  250.         }
  251.     }
  252.     return 0;
  253. }
  254.  
  255. /* set for unix end of line for remote echo mode telnet */
  256. int
  257. doeol(int argc,char **argv,void *p)
  258. {
  259.     if(argc < 2) {
  260.         tprintf("Eol %s\n",Tn_cr_mode ? "null" : "standard");
  261.     } else {
  262.         switch(*argv[1]) {
  263.             case 'n':
  264.                 Tn_cr_mode = 1;
  265.                 break;
  266.             case 's':
  267.                 Tn_cr_mode = 0;
  268.                 break;
  269.             default:
  270.                 tputs("Usage: eol <standard|null>\n");
  271.                 return -1;
  272.         }
  273.     }
  274.     return 0;
  275. }
  276.  
  277. #ifdef    __TURBOC__
  278. /* Set end-of-line translation mode on file */
  279. static int near
  280. filemode(FILE *fp,int mode)
  281. {
  282.     int omode = (fp->flags & _F_BIN) ? SOCK_BINARY : SOCK_ASCII;
  283.  
  284.     if(fp == NULLFILE)
  285.         return -1;
  286.  
  287.     switch(mode){
  288.     case SOCK_BINARY:
  289.         fp->flags = _F_BIN;
  290.         setmode(fileno(fp),O_BINARY);
  291.         break;
  292.     case SOCK_ASCII:
  293.         fp->flags &= ~_F_BIN;
  294.         setmode(fileno(fp),O_TEXT);
  295.         break;
  296.     }
  297.     return omode;
  298. }
  299. #else
  300. static int near
  301. filemode(FILE *fp,int mode)
  302. {
  303.     return 0;
  304. }
  305. #endif
  306.  
  307. /* The guts of the actual Telnet protocol: negotiating options */
  308. static void
  309. willopt(struct telnet *tn,int opt)
  310. {
  311.     int ack;
  312.  
  313. #ifdef    DEBUG
  314.     tputs("recv: will ");
  315.     if(uchar(opt) <= NOPTIONS)
  316.         tprintf("%s\n",T_options[opt]);
  317.     else
  318.         tprintf("%u\n",opt);
  319. #endif
  320.  
  321.     switch(uchar(opt)){
  322.     case TN_TRANSMIT_BINARY:
  323.     case TN_ECHO:
  324.     case TN_SUPPRESS_GA:
  325.         if(tn->remote[uchar(opt)] == 1)
  326.             return;        /* Already set, ignore to prevent loop */
  327.         if(uchar(opt) == TN_ECHO){
  328.             if(Refuse_echo){
  329.                 /* User doesn't want to accept */
  330.                 ack = DONT;
  331.                 break;
  332.             } else {
  333.                 /* Put tty into raw mode */
  334.                 tn->session->ttystate.edit = 0;
  335.                 tn->session->ttystate.echo = 0;
  336.                 sockmode(tn->session->s,SOCK_BINARY);
  337.                 sockmode(tn->session->input,SOCK_BINARY);
  338.                 sockmode(tn->session->output,SOCK_BINARY);
  339.                 if(tn->session->record != NULLFILE)
  340.                     filemode(tn->session->record,SOCK_BINARY);
  341.  
  342.             }
  343.         }
  344.         tn->remote[uchar(opt)] = 1;
  345.         ack = DO;
  346.         break;
  347.     default:
  348.         ack = DONT;    /* We don't know what he's offering; refuse */
  349.     }
  350.     answer(tn,ack,opt);
  351. }
  352.  
  353. static void
  354. wontopt(struct telnet *tn,int opt)
  355. {
  356. #ifdef    DEBUG
  357.     tputs("recv: wont ");
  358.     if(uchar(opt) <= NOPTIONS)
  359.         tprintf("%s\n",T_options[uchar(opt)]);
  360.     else
  361.         tprintf("%u\n",uchar(opt));
  362. #endif
  363.     if(uchar(opt) <= NOPTIONS){
  364.         if(tn->remote[uchar(opt)] == 0)
  365.             return;        /* Already clear, ignore to prevent loop */
  366.         tn->remote[uchar(opt)] = 0;
  367.         if(uchar(opt) == TN_ECHO){
  368.             /* Put tty into cooked mode */
  369.             tn->session->ttystate.edit = 1;
  370.             tn->session->ttystate.echo = 1;
  371.             sockmode(tn->session->s,SOCK_ASCII);
  372.             sockmode(tn->session->input,SOCK_ASCII);
  373.             sockmode(tn->session->output,SOCK_ASCII);
  374.             if(tn->session->record != NULLFILE)
  375.                 filemode(tn->session->record,SOCK_ASCII);
  376.         }
  377.     }
  378.     answer(tn,DONT,opt);    /* Must always accept */
  379. }
  380.  
  381. static void
  382. doopt(struct telnet *tn,int opt)
  383. {
  384.     int ack;
  385.  
  386. #ifdef    DEBUG
  387.     tputs("recv: do ");
  388.     if(uchar(opt) <= NOPTIONS)
  389.         tprintf("%s\n",T_options[uchar(opt)]);
  390.     else
  391.         tprintf("%u\n",uchar(opt));
  392. #endif
  393.     switch(uchar(opt)){
  394.     case TN_SUPPRESS_GA:
  395.         if(tn->local[uchar(opt)] == 1)
  396.             return;        /* Already set, ignore to prevent loop */
  397.         tn->local[uchar(opt)] = 1;
  398.         ack = WILL;
  399.         break;
  400.     default:
  401.         ack = WONT;    /* Don't know what it is */
  402.     }
  403.     answer(tn,ack,opt);
  404. }
  405.  
  406. static void
  407. dontopt(struct telnet *tn,int opt)
  408. {
  409. #ifdef    DEBUG
  410.     tputs("recv: dont ");
  411.     if(uchar(opt) <= NOPTIONS)
  412.         tprintf("%s\n",T_options[uchar(opt)]);
  413.     else
  414.         tprintf("%u\n",uchar(opt));
  415. #endif
  416.     if(uchar(opt) <= NOPTIONS){
  417.         if(tn->local[uchar(opt)] == 0){
  418.             /* Already clear, ignore to prevent loop */
  419.             return;
  420.         }
  421.         tn->local[uchar(opt)] = 0;
  422.     }
  423.     answer(tn,WONT,opt);
  424. }
  425.  
  426. static void
  427. answer(struct telnet *tn,int r1,int r2)
  428. {
  429.     char s[3];
  430.  
  431. #ifdef    DEBUG
  432.     switch(r1){
  433.     case WILL:
  434.         tputs("sent: will ");
  435.         break;
  436.     case WONT:
  437.         tputs("sent: wont ");
  438.         break;
  439.     case DO:
  440.         tputs("sent: do ");
  441.         break;
  442.     case DONT:
  443.         tputs("sent: dont ");
  444.         break;
  445.     }
  446.     if(r2 <= 6)
  447.         tprintf("%s\n",T_options[r2]);
  448.     else
  449.         tprintf("%u\n",r2);
  450. #endif
  451.  
  452.     s[0] = IAC;
  453.     s[1] = r1;
  454.     s[2] = r2;
  455.     send(tn->session->s,s,3,0);
  456. }
  457.  
  458.